import { App, Directive, DirectiveBinding } from "vue";

/**
 * Vue指令组件
 */
export default class DirectiveComponent {
    private static instance: DirectiveComponent = new DirectiveComponent();
    /**
     * Vue指令组件
     */
    public static get Default(): DirectiveComponent {
        return this.instance;
    }

    //#region drag

    private drag: Directive = {
        mounted: this.onDragMounted
    };

    private onDragMounted(element: HTMLElement, binding: DirectiveBinding) {

        function onMouseDown(downEvent: MouseEvent) {
            if (downEvent.button == 0) {
                let elementLeft = downEvent.clientX - element.offsetLeft;
                let elementTop = downEvent.clientY - element.offsetTop;
                const downEventTarget = downEvent.target as HTMLElement;
                if (downEventTarget.hasAttribute('drag-trigger')) {
                    function onMouseMove(moveEvent: MouseEvent) {
                        let left = moveEvent.clientX - elementLeft;
                        let top = moveEvent.clientY - elementTop;

                        let offsetWidth = 0;
                        let offsetHeight = 0;

                        if (binding.modifiers.offset) {
                            offsetWidth = element.clientWidth * 0;
                            offsetHeight = element.clientHeight * 0;
                        }

                        if (binding.modifiers.clamp) {
                            left = Math.min(Math.max(left, 0 + offsetWidth), window.innerWidth - element.offsetWidth + offsetWidth);
                            top = Math.min(Math.max(top, 0 + offsetHeight), window.innerHeight - element.offsetHeight + offsetHeight);
                        }

                        element.style.setProperty('position', `fixed`);
                        element.style.setProperty('left', `${left}px`);
                        element.style.setProperty('top', `${top}px`);
                        element.style.setProperty('right', `initial`);
                        element.style.setProperty('bottom', `initial`);
                    }

                    function onMouseUp(upEvent: MouseEvent) {
                        document.removeEventListener('mousemove', onMouseMove);
                        document.removeEventListener('mouseup', onMouseUp);
                    }

                    document.addEventListener('mousemove', onMouseMove);

                    document.addEventListener('mouseup', onMouseUp);
                }
            }

        }

        element.addEventListener('mousedown', onMouseDown);
    }

    //#endregion

    //#region wheel

    private wheel: Directive = {
        mounted: this.onWheelMounted
    };

    private onWheelMounted(element: HTMLElement, binding: DirectiveBinding) {
        function onWheel(wheelEvent: WheelEvent) {
            element.scrollLeft += wheelEvent.deltaY;
        }

        element.addEventListener('wheel', onWheel);
    }

    //#endregion

    public Register(app: App<Element>): void {
        app.directive('drag', this.drag);
        app.directive('wheel', this.wheel);
    }
}